package com.xzzz.expand.gateway.dr;

import com.xzzz.common.base.exception.XzException400;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory;
import org.springframework.cloud.gateway.route.RouteDefinition;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 提供路由校验等工具方法
 *
 * @author xzzz
 */
@Slf4j
public class RouteUtil {

    private List<GatewayFilterFactory> GatewayFilters;
    private List<RoutePredicateFactory> routePredicates;

    public RouteUtil(List<GatewayFilterFactory> gatewayFilters, List<RoutePredicateFactory> routePredicates) {
        this.GatewayFilters = gatewayFilters;
        this.routePredicates = routePredicates;
    }

    /**
     * 校验 routeDefinition 是否合法
     * @param routeDefinition 路由定义
     */
    public void validateRouteDefinition(RouteDefinition routeDefinition) {
        // 检查过滤器是否合法
        Set<String> unavailableFilterDefinitions = routeDefinition.getFilters().stream()
                .filter(rd -> !isAvailable(rd))
                .map(FilterDefinition::getName).collect(Collectors.toSet());

        // 检查谓词是否合法
        Set<String> unavailablePredicatesDefinitions = routeDefinition.getPredicates().stream()
                .filter(rd -> !isAvailable(rd)).map(PredicateDefinition::getName).collect(Collectors.toSet());

        // 如果过滤器不合法, 则报错
        if (!unavailableFilterDefinitions.isEmpty()) {
            final String errorMessage = String.format("不合法的 %s: %s", FilterDefinition.class.getSimpleName(), unavailableFilterDefinitions);
            log.debug(errorMessage);
            throw new XzException400(errorMessage);
        }

        // 如果谓词不合法, 则报错
        if (!unavailablePredicatesDefinitions.isEmpty()) {
            final String errorMessage = String.format("不合法的 %s: %s", PredicateDefinition.class.getSimpleName(), unavailablePredicatesDefinitions);
            log.debug(errorMessage);
            throw new XzException400(errorMessage);
        }
    }

    public boolean isAvailable(FilterDefinition filterDefinition) {
        return GatewayFilters.stream()
                .anyMatch(gatewayFilterFactory -> filterDefinition.getName().equals(gatewayFilterFactory.name()));
    }

    public boolean isAvailable(PredicateDefinition predicateDefinition) {
        return routePredicates.stream()
                .anyMatch(routePredicate -> predicateDefinition.getName().equals(routePredicate.name()));
    }
}
